package org.asiainfo.system.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import org.asiainfo.common.core.constant.Constants;
import org.asiainfo.common.core.constant.TenantConstants;
import org.asiainfo.common.core.constant.UserConstants;
import org.asiainfo.common.core.exception.ServiceException;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.idempotent.annotation.RepeatSubmit;
import org.asiainfo.common.log.annotation.Log;
import org.asiainfo.common.log.enums.BusinessType;
import org.asiainfo.common.satoken.utils.LoginHelper;
import org.asiainfo.system.domain.SysMenu;
import org.asiainfo.system.domain.vo.MenuTreeSelectVo;
import org.asiainfo.system.domain.vo.RouterVo;
import org.springframework.validation.annotation.Validated;
import org.asiainfo.system.service.SysMenuService;
import org.asiainfo.system.domain.vo.SysMenuVo;
import org.asiainfo.system.domain.bo.SysMenuBo;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.asiainfo.common.core.domain.R;
import org.asiainfo.common.web.core.BaseController;
import jakarta.validation.constraints.*;
import org.asiainfo.common.core.validate.AddGroup;
import org.asiainfo.common.core.validate.EditGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * 菜单权限表
 *
 * @author dotor-ww
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/menu")
public class SysMenuController extends BaseController {

    private final SysMenuService sysMenuService;

    /**
     * 获取菜单列表
     *
     * @param sysMenuBo 筛选条件
     * @return 查询结果
     */
    @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
    @SaCheckPermission("system:menu:list")
    @GetMapping("/list")
    public R<List<SysMenuVo>> list(SysMenuBo sysMenuBo) {
        return R.ok(sysMenuService.selectMenuList(sysMenuBo));
    }

    /**
     * 通过主键查询单条数据
     *
     * @param menuId 主键
     * @return 单条数据
     */
    @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
    @SaCheckPermission("system:menu:query")
    @GetMapping("/{menuId}")
    public R<SysMenuVo> getInfo(@NotNull(message = "菜单ID不能为空") @PathVariable("menuId") Long menuId) {
        return R.ok(sysMenuService.queryById(menuId));
    }

    /**
     * 获取菜单下拉菜单列表
     *
     * @param sysMenuBo 菜单信息
     * @return 下拉菜单
     */
    @SaCheckPermission("system:menu:query")
    @GetMapping("/treeSelect")
    public R<List<Tree<Long>>> treeSelect(SysMenuBo sysMenuBo) {
        List<SysMenuVo> sysMenuVos = sysMenuService.selectMenuList(sysMenuBo);
        return R.ok(sysMenuService.buildMenuTreeSelect(sysMenuVos));
    }

    /**
     * 获取带主类目的菜单下拉菜单列表
     *
     * @param sysMenuBo 菜单信息
     * @return 下拉菜单
     */
    @SaCheckPermission("system:menu:query")
    @GetMapping("/categories/treeSelect")
    public R<List<Tree<Long>>> treeSelectEx(SysMenuBo sysMenuBo) {
        List<SysMenuVo> sysMenuVos = sysMenuService.selectMenuList(sysMenuBo);
        Tree<Long> tree = new Tree<>();
        tree.setId(0L);
        tree.setName("主类目");
        tree.setWeight(0);
        tree.setChildren(sysMenuService.buildMenuTreeSelect(sysMenuVos));
        List<Tree<Long>> trees = new ArrayList<>();
        trees.add(tree);
        return R.ok(trees);
    }

    /**
     * 查询角色菜单列表
     *
     * @param roleId 角色ID
     * @return 菜单列表
     */
    @SaCheckPermission("system:menu:query")
    @GetMapping("/roleMenuTreeSelect/{roleId}")
    public R<MenuTreeSelectVo> roleMenuTreeSelect(@NotNull(message = "角色ID不能为空") @PathVariable("roleId") Long roleId) {
        List<SysMenuVo> sysMenuVos = sysMenuService.selectMenuList(new SysMenuBo());
        MenuTreeSelectVo menuTreeSelectVo = new MenuTreeSelectVo();
        menuTreeSelectVo.setCheckedKeys(sysMenuService.selectMenuListByRoleId(roleId));
        menuTreeSelectVo.setMenus(sysMenuService.buildMenuTreeSelect(sysMenuVos));
        return R.ok(menuTreeSelectVo);
    }

    /**
     * 新增数据
     *
     * @param sysMenuBo 实体
     * @return 新增结果
     */
    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
    @SaCheckPermission("system:menu:add")
    @Log(title = "菜单管理", businessType = BusinessType.INSERT)
    @RepeatSubmit
    @PostMapping
    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysMenuBo sysMenuBo) {
        if (sysMenuService.checkMenuNameUnique(sysMenuBo)) {
            throw new ServiceException("新增菜单'" + sysMenuBo.getMenuName() + "'失败，菜单名称已存在");
        } else if (UserConstants.YES_FRAME.equals(sysMenuBo.getIsFrame()) && !StringUtils.ishttp(sysMenuBo.getPath())) {
            throw new ServiceException("新增菜单'" + sysMenuBo.getMenuName() + "'失败，地址必须以http(s)://开头");
        }
        return toAjax(sysMenuService.insertByBo(sysMenuBo));
    }

    /**
     * 编辑数据
     *
     * @param sysMenuBo 实体
     * @return 编辑结果
     */
    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
    @SaCheckPermission("system:menu:edit")
    @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
    @RepeatSubmit
    @PutMapping
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysMenuBo sysMenuBo) {
        if (sysMenuService.checkMenuNameUnique(sysMenuBo)) {
            throw new ServiceException("新增菜单'" + sysMenuBo.getMenuName() + "'失败，菜单名称已存在");
        } else if (UserConstants.YES_FRAME.equals(sysMenuBo.getIsFrame()) && !StringUtils.ishttp(sysMenuBo.getPath())) {
            throw new ServiceException("新增菜单'" + sysMenuBo.getMenuName() + "'失败，地址必须以http(s)://开头");
        } else if (sysMenuBo.getMenuId().equals(sysMenuBo.getParentId())) {
            throw new ServiceException("父级菜单不能选择自己");
        }
        return toAjax(sysMenuService.updateByBo(sysMenuBo));
    }

    /**
     * 删除数据
     *
     * @param menuId 主键
     * @return 删除是否成功
     */
    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
    @SaCheckPermission("system:menu:remove")
    @Log(title = "菜单管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{menuId}")
    public R<Void> remove(@NotNull(message = "菜单ID不能为空") @PathVariable Long menuId) {
        if (sysMenuService.hasChildMenuByMenuId(menuId)) {
            throw new ServiceException("存在子菜单,不允许删除");
        }
        if (sysMenuService.checkMenuExistRole(menuId)) {
            throw new ServiceException("菜单已分配,不允许删除");
        }
        return toAjax(sysMenuService.deleteWithValidByIds(menuId));
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("/getRouters")
    public R<List<RouterVo>> getRouters() {
        List<SysMenu> sysMenus = sysMenuService.queryMenuTreeByUserId(LoginHelper.getUserId());
        return R.ok(sysMenuService.buildMenuTree(sysMenus));
    }

    /**
     * 租户套餐下菜单列表
     *
     * @param packageId 租户套餐ID
     * @return 菜单列表
     */
    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
    @SaCheckPermission("system:menu:query")
    @GetMapping("/tenantPackageMenuTreeSelect/{packageId}")
    public R<MenuTreeSelectVo> tenantPackageMenuTreeSelect(@NotNull(message = "租户套餐ID不能为空") @PathVariable Long packageId) {
        List<SysMenuVo> sysMenuVos = sysMenuService.selectMenuList(new SysMenuBo());
        MenuTreeSelectVo menuTreeSelectVo = new MenuTreeSelectVo();
        menuTreeSelectVo.setCheckedKeys(sysMenuService.selectMenuListByPackageId(packageId));
        menuTreeSelectVo.setMenus(sysMenuService.buildMenuTreeSelect(sysMenuVos));
        return R.ok(menuTreeSelectVo);
    }
}

